package com.xiaoyu.base.net;

import androidx.annotation.NonNull;

import com.xiaoyu.net.OkHttpClientSupplier;
import com.xiaoyu.net.progress.ProgressResponseBody;

import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.IOException;

import in.srain.cube.request.progress.ProgressListener;
import okhttp3.CacheControl;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.BufferedSink;
import okio.BufferedSource;
import okio.Okio;

public class OkHttpDownloader {

    private String mDownloadUrl;
    private String mDownloadFilePath;
    private Call mCall;
    private ProgressListener mProgressListener;
    private DownloadStatusListener mDownloadStatusListener;

    public OkHttpDownloader(@NonNull String downloadUrl, @NonNull String downloadFilePath) {
        this.mDownloadUrl = downloadUrl;
        this.mDownloadFilePath = downloadFilePath;
        initDownloader();
    }

    private void initDownloader() {
        final Request.Builder requestBuilder = new Request.Builder()
                .cacheControl(new CacheControl.Builder().noStore().build())
                .url(mDownloadUrl)
                .get();
        mCall = OkHttpClientSupplier.getResClient().newCall(requestBuilder.build());
    }

    public void setProgressListener(ProgressListener progressListener) {
        mProgressListener = progressListener;
    }

    public void setDownloadStatusListener(DownloadStatusListener downloadStatusListener) {
        mDownloadStatusListener = downloadStatusListener;
    }

    public void download() {
        mCall.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                if (mDownloadStatusListener != null) {
                    mDownloadStatusListener.onError(e);
                }
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) {
                if (mDownloadStatusListener != null) {
                    mDownloadStatusListener.onStart();
                }
                try {
                    ResponseBody responseBody = mProgressListener != null ? new ProgressResponseBody(response.body(), mProgressListener) : response.body();
                    BufferedSource source = responseBody.source();

                    File file = new File(mDownloadFilePath);
                    file.delete();
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                    file.createNewFile();

                    BufferedSink sink = Okio.buffer(Okio.sink(file));
                    source.readAll(sink);
                    sink.flush();
                    source.close();
                    if (mDownloadStatusListener != null) {
                        mDownloadStatusListener.onSuccess();
                    }
                } catch (Throwable throwable) {
                    if (mDownloadStatusListener != null) {
                        mDownloadStatusListener.onError(throwable);
                    }
                } finally {
                    if (mDownloadStatusListener != null) {
                        mDownloadStatusListener.onEnd();
                    }
                }
            }
        });
    }

    public void cancel() {
        if (mCall != null && !mCall.isCanceled()) {
            mCall.cancel();
        }
        if (mDownloadStatusListener != null) {
            mDownloadStatusListener.onCancel();
        }
    }

    public interface DownloadStatusListener {

        void onStart();

        void onSuccess();

        void onError(Throwable throwable);

        void onEnd();

        void onCancel();
    }
}
